#light

(* 
The transaction system is used for recording actions and playing them
backwards and forwards.  This will be the central aspect of undo/redo
throughout the application.

Actions can be considered general pieces of code that need to run to
bring the system back into synchronization with what it was before; they
do not need to pertain to the data model.

A transaction mainly wraps access to an action list.
A transaction system controls access to transaction ensuring that there 
is a central place to access the active transaction.

*)

namespace CGraph.Transactions

open CGraph.Generic
open CGraph.Generic.Impl
open System.Collections.Generic;
open System
    

/// Just an action list with a name.
type Transaction(m_name:string) =
    let m_list = new ActionList() :> IActionList
    let m_addFire,m_addEvt = IEvent.create<Transaction>()
    let m_doFire,m_doEvt = IEvent.create<Transaction>()
    let m_undoFire,m_undoEvt = IEvent.create<Transaction>()
    
    member s.AddEvent with get() = m_addEvt
    member s.DoEvent with get() = m_doEvt
    member s.UndoEvent with get() = m_undoEvt
        
    interface INamedObject with
        member s.Name with get() = m_name
    
    interface System.Collections.IEnumerable with
        member s.GetEnumerator() =
            (m_list :> System.Collections.IEnumerable).GetEnumerator()
        
    interface IActionList with
        member s.GetEnumerator() = 
            m_list.GetEnumerator();
            
        member s.Add ( act ) =
            m_list.Add(act);
            m_addFire(s)
            
        member s.Do() = 
            m_list.Do()
            m_doFire(s)
        
        member s.Undo() =
            m_list.Undo()
            m_undoFire(s)
            
        member this.OrderReversed with get() = m_list.OrderReversed;
    
    interface IDisposable with
        member s.Dispose() = 
            (m_list :?> IDisposable).Dispose()
            GC.SuppressFinalize s
    
    
        
type TransactionHandle(name:string) =
    let mutable m_trans = Some <| new Transaction(name)
    let m_commitFire,m_commitEvt = IEvent.create<Transaction>()
    member s.CommitEvent with get() = m_commitEvt
   
    member s.Transaction with get() = m_trans
    interface IDisposable with
        member s.Dispose() =
            m_commitFire(m_trans.Value)
            m_trans <- None
            GC.SuppressFinalize s
            
            
type TransactionSystem() =
    let m_openFire,m_openEvent = IEvent.create<Transaction>()
    let mutable m_transaction :Transaction option = None
    member s.Transaction = m_transaction
    member s.OpenEvent = m_openEvent
    member s.OpenTransaction name = 
        let retval = new TransactionHandle(name)
        m_transaction <- retval.Transaction
        retval.CommitEvent.Add( fun trans -> m_transaction <- None )
        m_openFire(retval.Transaction.Value)
        retval
        
    member s.AddAction (item:unit->IAction) =
        match m_transaction with
            | Some Trans -> (Trans :> IActionList).Add <| item()
            | None -> ()